<?php

namespace common\db;

use Yii;
use yii\base\InvalidConfigException;
use yii\db\ActiveQuery;
use yii\helpers\ArrayHelper;

/**
 * Description of SequenceActiveRecord
 *
 * @author emhome
 */
class SequenceActiveRecord extends ActiveRecord {

    public static $tablename = '';
    // 分表ID
    private static $partitionIndex = null;
    //
    public static $sequenceField = '';
    private static $sequenceFieldValue = null;

    const DELIMITER_CHAR = '_';

    /**
     * Mar constructor.
     * @param array $index
     * @param array $config
     */
    public function __construct($index = 0, $config = []) {
        self::resetPartitionIndex($index);
        parent::__construct($config);
    }

    /**
     * @return array|string
     */
    public static function tableName() {
        return '{{%' . static::$tablename . static::DELIMITER_CHAR . ltrim(self::$partitionIndex, static::DELIMITER_CHAR) . '}}';
    }

    /**
     * 重置分区id
     * @param unknown $index
     */
    private static function resetPartitionIndex($index = null) {
        if ($index && isset(Yii::$app->params['sequence'][static::$tablename])) {
            $partitionCount = Yii::$app->params['sequence'][static::$tablename];
            if ($index && $partitionCount) {
                self::$partitionIndex = $index % $partitionCount;
                self::$sequenceFieldValue = $index;
            }
        }
    }

    /**
     * @param $index
     * @return object
     * @throws InvalidConfigException
     */
    public static function findx($index) {
        self::resetPartitionIndex($index);
        $query = Yii::createObject(ActiveQuery::className(), [get_called_class(), ['from' => [static::tableName()]]]);
        return $query->andWhere([static::$sequenceField => self::$sequenceFieldValue]);
    }

    /**
     * @param array $row
     * @return static
     */
    public static function instantiate($row) {
        return new static(self::$partitionIndex);
    }

    /**
     * @param $table
     * @param $condition
     * @return mixed
     * @throws InvalidConfigException
     */
    public static function findOnex($table, $condition) {
        return static::findByConditionx($table, $condition)->one();
    }

    /**
     * @param $table
     * @param $condition
     * @return mixed
     * @throws InvalidConfigException
     */
    public static function findAllx($table, $condition) {
        return static::findByConditionx($table, $condition)->all();
    }

    /**
     * @param $table
     * @param $condition
     * @return mixed
     * @throws InvalidConfigException
     */
    protected static function findByConditionx($table, $condition) {
        $query = static::findx($table);

        if (!ArrayHelper::isAssociative($condition)) {
            // query by primary key
            $primaryKey = static::primaryKey();
            if (isset($primaryKey[0])) {
                $condition = [$primaryKey[0] => $condition];
            } else {
                throw new InvalidConfigException('"' . get_called_class() . '" must have a primary key.');
            }
        }

        return $query->andWhere($condition);
    }

    public function beforeSave($insert) {
        if (!parent::beforeSave($insert)) {
            return false;
        }
        if ($insert) {
            $this->generateSequenceId();
            $field = static::$sequenceField;
            $this->$field = self::$sequenceFieldValue;
        }
        return true;
    }

    private function generateSequenceId() {
        $sql = 'CALL p_sequence_id_gen("' . static::$tablename . '")';
        return $this->id = static::getDb()->createCommand($sql)->queryScalar();
    }

    public static function deleteAllX($table, $condition = [], $params = []) {
        self::resetPartitionIndex($table);
        return static::deleteAll($condition, $params);
    }

    public static function softDeleteAllX($table, $attributes = '', $condition = []) {
        self::resetPartitionIndex($table);
        if ($attributes) {
            return static::updateAll($attributes, $condition);
        }
        return static::updateAll(['deleted_at' => time()], $condition);
    }

}
